home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / comm / misc / New8n1.lha / 8n1_020.s < prev    next >
Text File  |  1996-12-14  |  59KB  |  1,908 lines

  1. ********************************************************************************
  2. **                                          **
  3. **  Name       : 8n1_020.s                              **
  4. **  Copyright  : © Copyright 96                           **
  5. **  Author     : Iain Barclay                              **
  6. **  Created    : 02 Dec 96                              **
  7. **  Version    : 37.26                                  **
  8. **                                          **
  9. ********************************************************************************
  10.      ;
  11.      ;      SNMA specific options
  12.      ;
  13.      IFD      SNMA
  14.      ;
  15.      CPU      M68030
  16.      ;
  17.      SNMAOPT  Q,A,M,T,E-,P,R,B
  18.      ;
  19.      ELSE
  20.      ; I have phxopts define this symbol
  21.      IFD PHXASS
  22.      machine 68030
  23.      OPT !
  24.      ENDC
  25.      ENDC
  26.      ;
  27.      ;
  28. DEBUG     SET      0
  29. NEWCODE  SET      1
  30. EOFCODE  SET      1
  31. SETDSR     SET      0
  32. NCOMM     SET      0
  33.      ;
  34.      ;
  35.      ;
  36.      SECTION  text,CODE
  37.      ;
  38.      ;
  39.      ;
  40. DEVICES_SERIAL_I_OBSOLETE  EQU        1
  41.      ;
  42.      ;
  43.      ;
  44.      INCLUDE  "exec/lists.i"
  45.      INCLUDE  "exec/memory.i"
  46.      INCLUDE  "exec/resident.i"
  47.      INCLUDE  "exec/devices.i"
  48.      INCLUDE  "exec/execbase.i"
  49.      INCLUDE  "exec/io.i"
  50.      INCLUDE  "exec/ports.i"
  51.      INCLUDE  "exec/errors.i"
  52.      INCLUDE  "exec/initializers.i"
  53.      INCLUDE  "intuition/preferences.i"
  54.      INCLUDE  "devices/timer.i"
  55.      INCLUDE  "devices/serial.i"
  56.      INCLUDE  "hardware/custom.i"
  57.      INCLUDE  "hardware/cia.i"
  58.      INCLUDE  "hardware/intbits.i"
  59.      INCLUDE  "hardware/adkbits.i"
  60.      INCLUDE  "resources/misc.i"
  61.      INCLUDE  "exec/alerts.i"
  62.      INCLUDE  "exec/macros.i"
  63.      INCLUDE  "8n1.device_rev.i"
  64.      ;
  65.      ;      Define hardware references
  66.      ;
  67.      XREF      _custom
  68.      XREF      _intena,_intenar,_intreq,_intreqr
  69.      XREF      _ciab,_ciabpra
  70.      XREF      _serper,_serdat,_serdatr
  71.      XREF      _adkcon,_adkconr
  72.      ;
  73.      ;      Exec Functions
  74.      ;
  75.      XREF      _LVORemDevice,_LVOOpenDevice,_LVOCloseDevice
  76.      XREF      _LVOSupervisor
  77.      XREF      _LVOAllocMem,_LVOFreeMem,_LVOCopyMem
  78.      XREF      _LVOReplyMsg
  79.      XREF      _LVOSendIO,_LVOAbortIO
  80.      XREF      _LVODisable,_LVOEnable
  81.      XREF      _LVOFindName
  82.      XREF      _LVOOpenResource
  83.      XREF      _LVOAddIntServer,_LVORemIntServer
  84.      XREF      _LVOAlert
  85.      XREF      _LVOOpenLibrary,_LVOCloseLibrary
  86.      ;
  87.      ;      Misc Resource Functions
  88.      ;
  89.      XREF      _LVOAllocMiscResource,_LVOFreeMiscResource
  90.      ;
  91.      ;      Intuition Functions
  92.      ;
  93.      XREF      _LVOGetPrefs
  94.      ;
  95.      ;      Mask used to get rid of the printer bits.
  96.      ;
  97. PRTMASK  EQU      (CIAF_PRTRPOUT|CIAF_PRTRBUSY)
  98.      ;
  99.      ;      Autovector offsets
  100.      ;
  101. LVL1VEC  EQU      (1-1)*4+$64
  102. LVL5VEC  EQU      (5-1)*4+$64
  103.      ;
  104.      ;      Device base
  105.      ;
  106.      STRUCTURE Base8n1,LIB_SIZE
  107.      UBYTE      vb_SaveDDRA
  108.      UBYTE      vb_SavePRA
  109.      APTR      vb_MiscBase
  110.      APTR      vb_OldLevel1
  111.      APTR      vb_OldLevel5
  112.      ULONG      vb_SegList
  113.      ULONG      vb_DefBaud
  114.      ULONG      vb_DefRBufLen
  115.      ULONG      vb_CurRBuf
  116.      ULONG      vb_CurRBufLen
  117.      ULONG      vb_CurBaud
  118.      UBYTE      vb_SerFlags
  119.      UBYTE      vb_Initialized
  120.      LABEL      sizeof_Base8n1
  121.      ;
  122.      ;
  123.      ;
  124. DISABLE  MACRO
  125.      IFNC      '\1',''
  126.      move.w   #INTF_\1,_intena
  127.      ELSE
  128.      jsr      _LVODisable(a6)
  129.      ENDC
  130.      ENDM
  131.      ;
  132. ENABLE     MACRO
  133.      IFNC      '\1',''
  134.      move.w   #INTF_SETCLR|INTF_\1,_intena
  135.      ELSE
  136.      jsr      _LVOEnable(a6)
  137.      ENDC
  138.      ENDM
  139.      ;
  140.      ;
  141.      ;
  142. Start:
  143.      moveq      #-1,d0                  ; set return code
  144.      rts                          ; return
  145.      ;
  146.      ;      RamLib looks for this romtag
  147.      ;
  148. ROMTag     DC.W      RTC_MATCHWORD               ; RT_MATCHWORD
  149.      DC.L      ROMTag                  ; RT_MATCHTAG
  150.      DC.L      ENDTag                  ; RT_ENDSKIP
  151.      DC.B      RTF_AUTOINIT                  ; RT_FLAGS
  152.      DC.B      VERSION                  ; RT_VERSION
  153.      DC.B      NT_DEVICE                  ; RT_TYPE
  154.      DC.B      0                      ; RT_PRI
  155.      DC.L      Name                      ; RT_NAME
  156.      DC.L      IdString                  ; RT_IDSTRING
  157.      DC.L      Init                      ; RT_INIT
  158.      ;
  159.      ;      Perform device initialization
  160.      ;
  161.     cnop 0,4    ; align for 020+
  162. InitRoutine:
  163.      exg      d0,a0                   ; swap seglist and base
  164.      move.l   d0,vb_SegList(a0)              ; store seglist in base
  165.      move.l   a6,SysBase                  ; store in global storage
  166.      exg      a0,d0                   ; swap them back
  167.      rts                          ; return
  168.      ;
  169.      ;
  170.      ;
  171.     cnop 0,4 ; align for 020+
  172. dev_Open:   ; (a1 iorequest, a5 will be Base8n1, a6 sysbase )
  173.      move.l   a5,-(sp)                  ; save registers
  174.      movea.l  a6,a5                   ; save base
  175.      movea.l  SysBase(pc),a6              ; get ExecBase
  176.      ;
  177.      tst.l      d0                      ; unit 0 specified?
  178.      bne.b      50$                      ; nope, error (who cares?)
  179.      ;
  180.      tst.w      LIB_OPENCNT(a5)              ; currently open?
  181.      bne.b      10$                      ; yep, go process
  182.      ;
  183.      move.b   IO_SERFLAGS(a1),vb_SerFlags(a5)     ; save flags
  184.      ;
  185.      tst.b      vb_Initialized(a5)              ; already initialized?
  186.      bne.b      40$                      ; yep, skip initialization
  187.      ;
  188.      bsr      initResources               ; go alloc resources
  189.      tst.l      d0                      ; initialized?
  190.      bne.b      50$                      ; nope, error
  191.      ;
  192.      bra.b      40$                      ; go exit
  193.      ;
  194.      cnop 0,4 ; align for 020+
  195. 10$     moveq      #SerErr_DevBusy,d0              ; preset error status
  196.      btst      #SERB_SHARED,vb_SerFlags(a5)          ; opened shared?
  197.      beq.b      50$                      ; nope, error
  198.      btst      #SERB_SHARED,IO_SERFLAGS(a1)          ; requesting shared?
  199.      beq.b      50$                      ; nope, error
  200.      ;
  201.      ;      Initialize I/O request
  202.      ;
  203. 40$     moveq      #8,d0                   ; get char size
  204.      move.b   d0,IO_READLEN(a1)              ; set read length
  205.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  206.      moveq      #1,d0                   ; get stop bits
  207.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  208.      move.b   IO_SERFLAGS(a1),d0
  209.      ori.b      #SERF_XDISABLED|SERF_RAD_BOOGIE|SERF_QUEUEDBRK|SERF_7WIRE,d0 ;flags
  210.      andi.b   #~(SERF_PARTY_ODD|SERF_PARTY_ON),d0 ; not used
  211.      move.b   d0,IO_SERFLAGS(a1)
  212.      move.l   vb_CurBaud(a5),IO_BAUD(a1)          ; set baud
  213.      move.l   vb_CurRBufLen(a5),IO_RBUFLEN(a1)    ; set read buffer length
  214.      ;
  215.      addq.w   #1,LIB_OPENCNT(a5)              ; incr open count
  216.      andi.b   #~(1<<LIBB_DELEXP),LIB_FLAGS(a5)    ; clear expunge bit
  217.      moveq      #0,d0                   ; no error
  218.      ;
  219. 50$     move.b   d0,IO_ERROR(a1)              ; store error code
  220.      movea.l  a5,a6                   ; restore base
  221.      move.l   (sp)+,a5                  ; restore registers
  222.      rts                          ; return
  223.      ;
  224.      ;      Attempt to allocate one of the serial resources.
  225.      ;
  226.      cnop 0,4 ; align for 020+
  227. allocResource:
  228.      move.l   a6,-(sp)                  ; save base pointer
  229.      move.l   d0,-(sp)                  ; save unit
  230.      lea.l      Name(pc),a1                  ; get lock name
  231.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  232.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  233.      tst.l      d0                      ; did we get it?
  234.      beq.b      20$                      ; yep, branch
  235.      ;
  236.      ;      It's in use, so we try to locate the device using the string
  237.      ;      returned and attempt to remove it.
  238.      ;
  239.      movea.l  SysBase(pc),a6              ; get ExecBase
  240.      ;
  241.      movea.l  d0,a1                   ; get ptr to serial name
  242.      lea.l      DeviceList(a6),a0              ; get ptr to device list
  243.      jsr      _LVOFindName(a6)              ; go find it
  244.      tst.l      d0                      ; found?
  245.      beq.b      10$                      ; nope, branch
  246.      ;
  247.      movea.l  d0,a1                   ; xfer device ptr
  248.      jsr      _LVORemDevice(a6)              ; remove it
  249.      ;
  250.      ;      We then retry the allocate.
  251.      ;
  252. 10$     move.l   (sp),d0                  ; get unit
  253.      lea.l      Name(pc),a1                  ; get lock name
  254.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  255.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  256.      ;
  257. 20$     addq.l   #4,sp                   ; restore stack ptr
  258.      movea.l  (sp)+,a6                  ; restore base ptr
  259.      rts                          ; return
  260.      ;
  261.      ;
  262.      ;
  263.      cnop 0,4 ; align for 020+
  264. initResources:    ; (a1 iorequest, a5 Base8n1, a6 sysbase )
  265.      move.l   a1,-(sp)                  ; save register
  266.      ;
  267.      lea.l      miscresource(pc),a1              ; ptr to resource name
  268.      jsr      _LVOOpenResource(a6)              ; go open it
  269.      move.l   d0,vb_MiscBase(a5)              ; save base
  270.      ;
  271.      moveq      #MR_SERIALPORT,d0              ; set unit number
  272.      bsr.b      allocResource               ; go allocate it
  273.      tst.l      d0                      ; did we get it?
  274.      bne.b      20$                      ; nope, error
  275.      ;
  276.      moveq      #MR_SERIALBITS,d0              ; set unit number
  277.      bsr.b      allocResource               ; go allocate it
  278.      tst.l      d0                      ; did we get it?
  279.      bne.b      10$                      ; nope, error
  280.      ;
  281.      bsr      getPrefs                  ; get default preferences
  282.      tst.l      d0                      ; got 'em?
  283.      beq.b      30$                      ; yep, branch
  284.      ;
  285.      moveq      #MR_SERIALBITS,d0              ; set unit
  286.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  287.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  288.      ;
  289. 10$     moveq      #MR_SERIALPORT,d0              ; set unit
  290.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  291.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  292.      movea.l  SysBase(pc),a6              ; restore ExecBase
  293.      ;
  294. 20$     moveq      #SerErr_DevBusy,d0              ; set error status
  295.      bra      40$                      ; go return
  296.      ;
  297.      cnop 0,4 ; align for 020+
  298. 30$     moveq      #0,d1                   ; clear flags
  299.      moveq      #UNIT_VBLANK,d0              ; set unit
  300.      lea.l      timerReq(pc),a1              ; ptr to timer request
  301.      lea.l      timerdevice(pc),a0              ; ptr to device name
  302.      jsr      _LVOOpenDevice(a6)              ; go open it
  303.      ;
  304.  
  305.      DISABLE                      ; disable interrupts
  306.      ;
  307.      lea.l      _ciab,a1                  ; get ptr to ciab
  308.      move.b   ciaddra(a1),d0
  309.      move.b   d0,vb_SaveDDRA(a5)              ; save DDR value
  310.      andi.b   #PRTMASK,d0                  ; make serial bits input
  311.      move.b   (a1),d1                  ; ciapra(a1)
  312.      ori.b      #CIAF_COMDTR|CIAF_COMRTS,d0          ; make DTR/RTS output
  313.      move.b   d1,vb_SavePRA(a5)              ; save PR value
  314.      andi.b   #CIAF_COMDTR|CIAF_COMRTS|PRTMASK,d0 ; turn on DTR/RTS
  315.      move.b   d0,ciaddra(a1)
  316.      andi.b   #CIAF_COMCTS|CIAF_COMDSR|PRTMASK,d1 ; make CTS/DSR input
  317.      move.b   d1,(a1)                  ; ciapra(a1)
  318.      ;
  319.      moveq      #INTB_PORTS,d0              ; get interrupt number
  320.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  321.      jsr      _LVOAddIntServer(a6)              ; add it to the list
  322.      ;
  323.      bsr      getVBR                  ; get vector base (in A0)
  324.      ;
  325.      move.l   LVL1VEC(a0),vb_OldLevel1(a5)          ; save original vector
  326.      lea.l      level1(pc),a1               ; get new vector ptr
  327.      move.l   a1,LVL1VEC(a0)              ; set new vector
  328.      ;
  329.      move.l   LVL5VEC(a0),vb_OldLevel5(a5)          ; save original vector
  330.      lea.l      level5(pc),a1               ; get new vector ptr
  331.      move.l   a1,LVL5VEC(a0)              ; set new vector
  332.      ;
  333.      lea.l      _custom,a1                  ; get ptr to custom chips
  334.      move.w   #INTF_RBF|INTF_TBE,intreq(a1)       ; clear pending interrupts
  335.      move.w   #INTF_SETCLR|INTF_RBF|INTF_TBE,intena(a1) ; enable RBF & TBE
  336.      ;
  337.      addq.b   #1,vb_Initialized(a5)           ; set flag
  338.      moveq      #0,d0                   ; set good status
  339.      ;
  340.      ENABLE                       ; enable interrupts
  341.      ;
  342. 40$     movea.l  (sp)+,a1                  ; restore register
  343.      rts                          ; return
  344.      ;
  345.      ;      Get system preferences
  346.      ;
  347.      cnop 0,4 ; align for 020+
  348. getPrefs:
  349.      move.l   a1,-(sp)                  ; save registers
  350.      ;
  351.      lea.l      intuitlib(pc),a1              ; ptr to library name
  352.      moveq      #0,d0                   ; can't use OldOpenLibrary as this will not be supported.
  353.      jsr      _LVOOpenLibrary(a6)              ; go open it (any version)
  354.      movea.l  d0,a6                   ; get intuition base
  355.      ;
  356.      move.l   #(pf_SerParShk+3)&$fffffffc,d0      ; size we need (aligned)
  357.      suba.l   d0,sp                   ; reserve space
  358.      ;
  359.      movea.l  sp,a0                   ; set data area ptr
  360.      jsr      _LVOGetPrefs(a6)              ; get preferences
  361.      ;
  362.      movea.l  a6,a1                   ; get intuition base
  363.      movea.l  SysBase(pc),a6              ; restore ExecBase
  364.      jsr      _LVOCloseLibrary(a6)              ; close it
  365.      ;
  366.      moveq      #$0f,d1                  ; set mask
  367.      and.b      pf_SerStopBuf(sp),d1              ; get bufsize index
  368.      addq.l   #8,d1                   ; calc shift value
  369.      moveq      #2,d0                   ; get 1<<1
  370.      lsl.l      d1,d0                   ; get default bufsize
  371.      move.l   d0,vb_DefRBufLen(a5)              ; and store
  372.      ;
  373.      moveq      #0,d1                   ; clear upper half
  374.      move.w   pf_BaudRate(sp),d1              ; get baud rate
  375.      move.w   baudTable(pc,d1.w*2),d1          ; get baud rate
  376.      move.l   d1,vb_DefBaud(a5)              ; and store
  377.      ;
  378.      bsr      internalReset               ; go init baud and buffer
  379.      ;
  380.      lea.l      (pf_SerParShk+3)&$fffffffc(sp),sp   ; restore stack
  381.      movea.l  (sp)+,a1                  ; restore registers
  382.      rts                          ; return ( status in D0 )
  383.      ;
  384.      ;      Preferences baud lookup table
  385.      ;
  386. baudTable:
  387.      dc.w      112,300,1200,2400,4800,9600,19200,31250,38400,57600,62400,64800
  388.      ;
  389.      ;      Set exception vectors
  390.      ;
  391.      cnop 0,4 ; align for 020+
  392. getVBR:
  393.      move.l   a5,-(sp)                  ; save registers
  394.      lea.l      20$(pc),a5                  ; ptr to routine
  395.      jsr      _LVOSupervisor(a6)              ; get into supervisor state
  396. 10$     movea.l  (sp)+,a5                  ; restore register
  397.      rts                          ; return
  398. 20$     movec.l  vbr,a0                  ; get vector base
  399.      rte                          ; return
  400.      ;
  401.      ;
  402.      ;
  403.      cnop 0,4 ; align for 020+
  404. freeResources:
  405.      move.l   a1,-(sp)                  ; save registers
  406.      ;
  407.      DISABLE                      ; disable interrupts
  408.      ;
  409.      bsr.b      getVBR                  ; get vector base (in A0)
  410.      ;
  411.      moveq      #1,d0                   ; set not restored code
  412.      ;
  413.      lea.l      level1(pc),a1               ; get our vector ptr
  414.      cmpa.l   LVL1VEC(a0),a1              ; do they match?
  415.      bne      10$                      ; nope, can't restore
  416.      ;
  417.      lea.l      level5(pc),a1               ; get our vector ptr
  418.      cmpa.l   LVL5VEC(a0),a1              ; do they match?
  419.      bne      10$                      ; nope, can't restore
  420.      ;
  421.      move.l   vb_OldLevel1(a5),LVL1VEC(a0)          ; restore original vector
  422.      move.l   vb_OldLevel5(a5),LVL5VEC(a0)          ; restore original vector
  423.      ;
  424.      moveq      #INTB_PORTS,d0              ; get interrupt number
  425.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  426.      jsr      _LVORemIntServer(a6)              ; remove it from the list
  427.      ;
  428.      lea.l      _custom,a0                  ; get custom base
  429.      move.w   #INTF_RBF|INTF_TBE,d0           ; indicate serial interrupts
  430.      move.w   d0,intena(a0)               ; disable interrupts
  431.      move.w   d0,intreq(a0)               ; clear pending interrupts
  432.      ;
  433.      bsr      freeBuf                  ; free allocated buffers
  434.      ;
  435.      lea.l      _ciab,a0                  ; get pointer to ciab
  436.      move.b   ciaddra(a0),d0              ; get DDR value
  437.      andi.b   #PRTMASK,d0                  ; save printer bits
  438.      ori.b      #~PRTMASK,d0                  ; set serial bits to output
  439.      move.b   d0,ciaddra(a0)              ; store value
  440.      ;
  441.      move.b   (a0),d0                  ; get PR value ( ciapra(a0) )
  442.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  443.      move.b   vb_SavePRA(a5),d1              ; get saved value
  444.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  445.      or.b      d1,d0                   ; combine the two
  446.      move.b   d0,(a0)                  ; and store ( ciapra(a0) )
  447.      ;
  448.      move.b   ciaddra(a0),d0              ; get DDR value
  449.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  450.      move.b   vb_SaveDDRA(a5),d1              ; get saved value
  451.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  452.      or.b      d1,d0                   ; combine the two
  453.      move.b   d0,ciaddra(a0)              ; and store
  454.      ;
  455.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  456.      jsr      _LVOCloseDevice(a6)              ; go close it
  457.      ;
  458.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  459.      moveq      #MR_SERIALBITS,d0              ; set unit
  460.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  461.      ;
  462.      moveq      #MR_SERIALPORT,d0              ; set unit
  463.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  464.      movea.l  SysBase(pc),a6              ; restore ExecBase
  465.      ;
  466.      ENABLE                       ; enable interrupts
  467.      ;
  468.      subq.b   #1,vb_Initialized(a5)           ; clear flag
  469.      moveq      #0,d0                   ; free up everything
  470.      ;
  471. 10$     movea.l  (sp)+,a1                  ; restore registers
  472.      rts                          ; return
  473.      ;
  474.      ;      Device Close routine
  475.      ;
  476.      cnop 0,4 ; align for 020+
  477. dev_Close:
  478.      ;
  479.      moveq      #-1,d0                  ; invalidate
  480.      move.l   d0,IO_DEVICE(a1)              ;   device
  481.      ;
  482.      subq.w   #1,LIB_OPENCNT(a6)              ; decr open count
  483.      bne.b      dev_Null                  ; still open? yep, branch
  484.      ;
  485.      move.l   a5,-(sp)                  ; save registers
  486.      movea.l  a6,a5                   ; save base
  487.      movea.l  SysBase(pc),a6              ; get ExecBase
  488.      ;
  489.      bsr      freeResources               ; free allocated resources
  490.      ;
  491.      movea.l  a5,a6                   ; restore base
  492.      movea.l  (sp)+,a5                  ; restore registers
  493.      ;
  494.      tst.l      d0                      ; freed?
  495.      bne.b      dev_Null                  ; nope, can't expunge, exit
  496.      ;
  497.      clr.b      vb_SerFlags(a6)              ; clear flags
  498.      ;
  499.      btst      #LIBB_DELEXP,LIB_FLAGS(a6)          ; delayed expunge set?
  500.      beq.b      dev_Null                  ; nope, go exit
  501.      bra.b      dev_Expunge
  502.      ;
  503.      ;      Device Expunge routine (also fall through from dev_Close)
  504.      ;
  505.      cnop 0,4 ; align for 020+
  506. dev_Expunge:
  507.      ori.b      #1<<LIBB_DELEXP,LIB_FLAGS(a6)       ; Set expunge flag
  508.      tst.w      LIB_OPENCNT(a6)              ; currently open?
  509.      bne.b      dev_Null                  ; yep, so just exit
  510.      ;
  511.      move.l   vb_SegList(a6),d0              ; get seglist ptr
  512.      move.l   d0,-(sp)                  ; save registers (save D0!)
  513.      ;
  514.      movea.l  a6,a1                   ; get base
  515.      ; This is the REMOVE macro
  516.      move.l   (a1)+,a0
  517.      move.l   (a1),a1                  ; LN_PRED
  518.      move.l   a0,(a1)
  519.      move.l   a1,LN_PRED(a0)
  520.      ;
  521.      movea.l  a6,a1                   ; get base
  522.      moveq      #0,d0                   ; clear work
  523.      move.w   LIB_NEGSIZE(a6),d0              ; calculate
  524.      suba.w   d0,a1                   ;   memory address
  525.      add.w      LIB_POSSIZE(a6),d0              ;     and size
  526.      move.l   a6,-(sp)                  ; save registers
  527.      movea.l  SysBase(pc),a6              ; get ExecBase
  528.      jsr      _LVOFreeMem(a6)              ; free it
  529.      ;
  530.      move.l   (sp)+,a6                  ; restore registers
  531.      move.l   (sp)+,d0                  ; restore registers
  532. exp_end  rts                          ; return (seglist in D0!)
  533.      ;
  534.      ;      Device "ExtFunc" routine
  535.      ;
  536.      cnop 0,4 ; align for 020+
  537. dev_Null:
  538.      moveq      #0,d0                   ; set return code
  539.      bra.b      exp_end                  ; return
  540.      ;
  541.      ;
  542.      cnop 0,4 ; align for 020+
  543. cmdTable dc.w      cmd_Invalid-cmdTable              ; CMD_INVALID
  544.      dc.w      cmd_Reset-cmdTable              ; CMD_RESET
  545.      dc.w      cmd_Read-cmdTable              ; CMD_READ
  546.      dc.w      cmd_Write-cmdTable              ; CMD_WRITE
  547.      dc.w      cmd_Invalid-cmdTable              ; CMD_UPDATE
  548.      dc.w      cmd_Clear-cmdTable              ; CMD_CLEAR
  549.      dc.w      cmd_Invalid-cmdTable              ; CMD_STOP
  550.      dc.w      cmd_Invalid-cmdTable              ; CMD_START
  551.      dc.w      cmd_Flush-cmdTable              ; CMD_FLUSH
  552.      dc.w      sdcmd_Query-cmdTable              ; SDCMD_QUERY
  553.      dc.w      sdcmd_Break-cmdTable              ; SDCMD_BREAK
  554. endTable dc.w      sdcmd_SetParams-cmdTable          ; SDCMD_SETPARAMS
  555.      ;
  556.      ;      Device BeginIO routine
  557.      ;
  558.      cnop 0,4 ; align for 020+
  559. dev_BeginIO:
  560.      move.l   a5,-(sp)                  ; save register
  561.      movea.l  a6,a5                   ; save base
  562.      movea.l  SysBase(pc),a6              ; get ExecBase
  563.      ;
  564.      move.b   #NT_MESSAGE,LN_TYPE(a1)          ; set type
  565.      clr.b      IO_ERROR(a1)                  ; clear error
  566.      ;
  567.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),IO_FLAGS(a1) ; clear flags
  568.      ;
  569.      move.w   IO_COMMAND(a1),d0              ; get command
  570.      add.w      d0,d0                   ; multiply by 2
  571.      cmpi.w   #endTable-cmdTable,d0           ; in range?
  572.      bhi.b      30$                      ; nope, error
  573.      ;
  574.      move.w   cmdTable(pc,d0.w),d0              ; get routine offset
  575.      jsr      cmdTable(pc,d0.w)              ; go do it
  576.      tst.l      d0                      ; I/O completed?
  577.      bne.b      19$                      ; nope, go return
  578.      ;
  579. 10$
  580.      btst      #IOB_QUICK,IO_FLAGS(a1)          ; need to reply?
  581.      bne.b      20$                      ; nope, branch
  582. 15$     jsr      _LVOReplyMsg(a6)              ; send it back
  583.      ;
  584. 19$     andi.b   #~(1<<IOB_QUICK),IO_FLAGS(a1)       ; clear quick bit
  585. 20$     movea.l  a5,a6                   ; restore base
  586.      movea.l  (sp)+,a5                  ; restore register
  587.      rts                          ; return
  588.      ;
  589. 30$     move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; invalid command
  590.      bra.b      10$                      ; branch
  591.      ;
  592.      ;      Device AbortIO routine
  593.      ;
  594.      cnop 0,4 ; align for 020+
  595. dev_AbortIO:
  596.      move.l   a5,-(sp)                  ; save registers
  597.      movea.l  a6,a5                   ; save base
  598.      movea.l  SysBase(pc),a6              ; get ExecBase
  599.      ;
  600.      DISABLE                      ; disable interrupts
  601.      ;
  602.      move.b   IO_FLAGS(a1),d1              ; get flags
  603.      btst      #IOSERB_QUEUED,d1              ; queued request?
  604.      bne.b      40$                      ; yep, branch
  605.      ;
  606.      btst      #IOSERB_ACTIVE,d1              ; active request?
  607.      bne.b      10$                      ; nope, just exit
  608.      ;
  609.      move.w   IO_COMMAND(a1),d0              ; get command
  610.      subq.w   #CMD_READ,d0                  ; was it a read?
  611.      beq.b      20$                      ; yep, go process
  612.      ;
  613.      subq.w   #CMD_WRITE-CMD_READ,d0          ; was it a write?
  614.      beq.b      30$                      ; yep, go process
  615.      ;
  616.      subq.w   #SDCMD_BREAK-CMD_WRITE,d0          ; was it a break?
  617.      beq.b      30$                      ; yep, go process
  618.      ;
  619.      ;      Fall through or enter from below
  620.      ;
  621. 10$     ENABLE                       ; enable ints and return
  622. 15$     movea.l  a5,a6                   ; restore base
  623.      movea.l  (sp)+,a5                  ; restore registers
  624.      rts                          ; return
  625.      ;
  626.      ;      Abort an active read request
  627.      ;
  628. 20$     clr.l      cr_IOReq                  ; no longer active
  629.      bra.b      50$                      ; go set flags
  630.      ;
  631.      ;      Abort an active write request
  632.      ;
  633.      cnop 0,4 ; align for 020+
  634. 30$     clr.l      cw_Length                  ; no longer active
  635.      clr.l      cw_IOReq                  ; no longer active
  636.      move.l   cw_Buffer(pc),d0              ; get buffer ptr
  637.      sub.l      IO_DATA(a1),d0              ; calc number of bytes xfer'd
  638.      move.l   d0,IO_ACTUAL(a1)              ; store
  639.      ;
  640.      ;      Force a TBE interrupt to get the next write going.
  641.      ;
  642.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  643.      bra.b      50$                      ; go set flags
  644.      ;
  645.      ;      Remove I/O from queue.
  646.      ;
  647.      cnop 0,4 ; align for 020+
  648. 40$     move.l   a1,-(sp)                  ; save ptr
  649.      ; This is the REMOVE macro
  650.      move.l   (a1)+,a0
  651.      move.l   (a1),a1                  ; LN_PRED
  652.      move.l   a0,(a1)
  653.      move.l   a1,LN_PRED(a0)
  654.      ;
  655.      movea.l  (sp)+,a1                  ; restore ptr
  656.      ;
  657.      ;      Set error and return I/O
  658.      ;
  659. 50$     move.b   #IOERR_ABORTED,IO_ERROR(a1)          ; set error code
  660.      move.b   IO_FLAGS(a1),d1              ; get flags
  661.      ori.b      #1<<IOSERB_ABORT,d1              ; set abort flag
  662.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),d1  ; clear flags
  663.      move.b   d1,IO_FLAGS(a1)              ; store flags
  664.      btst      #IOB_QUICK,d1               ; need to reply?
  665.      bne.b      10$                      ; nope, branch
  666.      jsr      _LVOReplyMsg(a6)              ; send it back
  667.      bra.b      10$                      ; branch to return
  668.      ;
  669.      ;      Abort all active/queued commands and reset internal state
  670.      ;
  671.      cnop 0,4 ; align for 020+
  672. cmd_Reset:
  673.      move.l   a1,-(sp)                  ; save I/O request
  674.      bsr.b      cmd_Flush                  ; go abort queued requests
  675.      ;
  676.      DISABLE                      ; disable interrupts
  677.      ;
  678.      ;      This must follow the DISABLE
  679.      ;
  680.      exg      a5,a6                   ; exchange base and ExecBase
  681.      ;
  682.     IFNE NEWCODE
  683.      move.l   cr_IOReq(pc),a1              ; active read?
  684.      beq.b      10$                      ; nope, branch
  685.     ELSE
  686.      move.l   cr_IOReq(pc),d0              ; active read?
  687.      beq.b      10$                      ; nope, branch
  688.      movea.l  d0,a1                   ; get I/O request
  689.     ENDC
  690.      bsr      dev_AbortIO                  ; go abort it
  691.      ;
  692.      ;
  693.      ;
  694.     IFNE NEWCODE
  695. 10$     move.l   cw_IOReq(pc),a1              ; active write?
  696.      beq.b      20$                      ; nope, branch
  697.     ELSE
  698. 10$     move.l   cw_IOReq(pc),d0              ; active write?
  699.      beq.b      20$                      ; nope, branch
  700.      movea.l  d0,a1                   ; get I/O request
  701.     ENDC
  702.      bsr      dev_AbortIO                  ; go abort it
  703.      ;
  704. 20$     exg      a5,a6                   ; restore base and ExecBase
  705.      movea.l  (sp)+,a1                  ; restore I/O request
  706.      moveq      #8,d0                   ; get char size
  707.      move.b   d0,IO_READLEN(a1)              ; set read length
  708.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  709.      moveq      #1,d0                   ; get stop bits
  710.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  711.      move.l   vb_DefBaud(a5),IO_BAUD(a1)          ; set to default baud
  712.      move.l   vb_DefRBufLen(a5),IO_RBUFLEN(a1)    ; set to default buflen
  713.      bsr      internalReset               ; go set/verify parameters
  714.      move.b   d0,IO_ERROR(a1)              ; set error code
  715.      ENABLE                       ; enable interrupts
  716.      ;
  717.      ;      Set RC and return
  718.      ;
  719.      moveq      #0,d0                   ; I/O complete
  720.      rts                          ; return
  721.      ;
  722.      ;      Abort all "queued" requests, leaving all active alone.
  723.      ;
  724.      cnop 0,4 ; align for 020+
  725. cmd_Flush:
  726.      movem.l  a1/a2,-(sp)                  ; save registers
  727.      DISABLE                      ; disable interrupts
  728.      ;
  729.      ;      Abort all queued read requests.
  730.      ;
  731.      lea.l      readQ(pc),a2                  ; get ptr to read queue
  732.      bsr.b      20$                      ; branch to abort
  733.      ;
  734.      ;      Abort all queued write requests.
  735.      ;
  736.      lea.l      writeQ(pc),a2               ; get ptr to write queue
  737.      bsr.b      20$                      ; branch to abort
  738.      ;
  739.      ;      Enable, restore, and return to caller
  740.      ;
  741.      ENABLE                       ; enable interrupts
  742.      movem.l  (sp)+,a1/a2                  ; restore registers
  743.      ;
  744.      ;      Set RC and return
  745.      ;
  746.      moveq      #0,d0                   ; I/O complete
  747.      ;
  748.      ;      !!!NOTE!!!  In a mad attempt to save 2 bytes, this RTS is used
  749.      ;      by the subroutine below.  Why waste 'em?  B-)
  750.      ;
  751. 10$     rts                          ; return ( used below too!! )
  752.      ;
  753.      ;      Subroutine to remove and reply each I/O request.
  754.      ;
  755.      cnop 0,4 ; align for 020+
  756. 20$     movea.l  a2,a0                   ; get list ptr
  757.      ; This is the REMHEAD macro
  758. 25$     move.l   (a0),a1
  759.      move.l   (a1),d0
  760.      beq.b      25$
  761.      move.l   d0,(a0)
  762.      exg.l      d0,a1
  763.      move.l   a0,LN_PRED(a1)
  764.      ;
  765.      tst.l      d0                      ; end of list?
  766.      beq.b      10$                      ; yep, branch to return
  767.      ;
  768.      movea.l  d0,a1                   ; get I/O request
  769.      andi.b   #~(1<<IOSERB_QUEUED),IO_FLAGS(a1)   ; no longer queued
  770.      moveq      #IOERR_ABORTED,d0              ; indicate aborted
  771.      move.b   d0,IO_ERROR(a1)              ; store status
  772.      ;
  773.      jsr      _LVOReplyMsg(a6)              ; send it back
  774.      bra.b      20$                      ; continue with next
  775.      ;
  776.      ;      Process a CMD_READ request.
  777.      ;
  778.      cnop 0,4 ; align for 020+
  779. cmd_Read:
  780.      ;
  781.      ;      Zero length requests just get returned.
  782.      ;
  783.      clr.l      IO_ACTUAL(a1)               ; clear bytes read
  784.      move.l   IO_LENGTH(a1),d0              ; get length and test
  785.      beq.b      20$                      ; yep, leave
  786.      ;
  787.      ;      This can be used to circumvent a bug in NComm 3.0 which
  788.      ;      references the buffer even when there was nothing read.
  789.      ;
  790.     IFNE     NCOMM
  791.      move.l   IO_DATA(A1),a0              ; get data pointer
  792.      clr.b      (a0)                      ; clear first byte in buffer
  793.     ENDC
  794.      ;
  795.      ;      The disable counter works just like exec's TDNestCnt field.  It's
  796.      ;      initialized to -1.  After incrementing, if it is 0, then we
  797.      ;      can attempt to process this request immediately.  If it's > 0,
  798.      ;      then we're already disabled and we must queue this request.
  799.      ;
  800.      addq.b   #1,disableRead              ; incr disable count
  801.      bgt.b      50$                      ; >0, already disabled
  802.      ;
  803.      ;      If we're already processing an request, this one has to wait
  804.      ;      until that one is done, so go queue it.
  805.      ;
  806.      tst.l      cr_IOReq(pc)                  ; have an active request?
  807.      bne.b      50$                      ; yep, go queue this one
  808.      ;
  809.      ;      If we don't have enough bytes to satisfy this request then go
  810.      ;      queue it.
  811.      ;
  812.      cmp.l      i_InCnt(pc),d0              ; length > current bytes?
  813.      bgt.b      50$                      ; yep, go queue it
  814.      ;
  815.      ;      Setup fields and go copy the data
  816.      ;
  817.      move.l   IO_DATA(a1),cr_OutPtr           ; get/set output ptr
  818.      move.l   IO_LENGTH(a1),cr_Length          ; get/set output count
  819.      bsr      copyData                  ; go copy 'em
  820.      moveq      #0,d0                   ; I/O complete
  821.      ;
  822.      ;      We're done, so back off the disable counter.
  823.      ;
  824. 10$     subq.b   #1,disableRead              ; decr disable count
  825.      ;
  826.      ;      Return to caller
  827.      ;
  828. 20$     rts                          ; return
  829.      ;
  830.      ;      Just set flags and queue.  The read interrupt will handle it.
  831.      ;
  832. 50$     ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)    ; indicate queued
  833.      ;
  834.      ;      Add this request to the end.
  835.      ;
  836.      DISABLE                      ; disable interrupts
  837.      lea.l      readQ(pc),a0                  ; get pointer to read queue
  838.      ; This is the ADDTAIL macro
  839.      addq.l   #LH_TAIL,a0
  840.      move.l   LN_PRED(a0),d0
  841.      move.l   a1,LN_PRED(a0)
  842.      EXG      d0,a0
  843.      movem.l  d0/a0,(a1)
  844.      move.l   a1,(a0)
  845.      ;
  846.      ENABLE                       ; enable interrupts
  847.      ;
  848.      ;      Indicate that this request was not handled immediatly.
  849.      ;
  850.      moveq      #1,d0                   ; I/O not complete
  851.      bra.b      10$                      ; branch to return
  852.      ;
  853.      ;      Process a CMD_WRITE request.
  854.      ;
  855.      cnop 0,4 ; align for 020+
  856. cmd_Write:
  857.      clr.l      IO_ACTUAL(a1)               ; clear bytes written
  858.      tst.l      IO_LENGTH(a1)               ; get length and test
  859.      beq.b      wbexit                  ; yep, leave
  860.      ;
  861.      ;      Entry point for Break command and fall through from cmd_Write.
  862.      ;
  863. sdcmd_Break:
  864.      ;
  865.      ;      Just set flags and queue. The TBE interrupt will handle it.
  866.      ;
  867.      ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)     ; indicate queued
  868.      ;
  869.      ;      Protect.
  870.      ;
  871.      DISABLE                      ; disable interrupts
  872.      ;
  873.      ;      Add request to end of queue.
  874.      ;
  875.      lea.l      writeQ(pc),a0               ; get queue list ptr
  876.      ; This is the ADDTAIL macro
  877.      addq.l   #LH_TAIL,a0
  878.      move.l   LN_PRED(a0),d0
  879.      move.l   a1,LN_PRED(a0)
  880.      EXG      d0,a0
  881.      movem.l  d0/a0,(a1)
  882.      move.l   a1,(a0)
  883.      ;
  884.      ;      If we have an active request, don't force interrupt.
  885.      ;
  886.      tst.l      cw_IOReq(pc)                  ; have an active request?
  887.      bne.b      10$                      ; yep, branch
  888.      ;
  889.      ;      Force a TBE interrupt to get the writes going.
  890.      ;
  891.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  892.      ;
  893.      ;      Enable, set RC and return to caller.
  894.      ;
  895. 10$     ENABLE                       ; enable interrupts
  896.      moveq      #1,d0                   ; I/O not complete
  897. wbexit     rts                          ; return
  898.      ;
  899.      ;      Resets serial read buffer
  900.      ;
  901.      ;      Since this routine is called internally, it must NOT reference
  902.      ;      the I/O request.
  903.      ;
  904.      cnop 0,4 ; align for 020+
  905. cmd_Clear:
  906.      DISABLE                      ; disable interrupts
  907.      ;
  908.      ;      Load registers
  909.      ;
  910.      move.l   vb_CurRBuf(a5),d0              ; get internal buffer ptr
  911.      move.l   vb_CurRBufLen(a5),d1              ; and internal buffer len
  912.      lea.l      i_BufPtr(pc),a0              ; get ptr internal control
  913.      ;
  914.      ;      Initialize global buffer variables
  915.      ;
  916.      move.l   d0,(a0)                  ; store buffer ptr
  917.      move.l   d0,4(a0)                  ; set current input ptr
  918.      move.l   d0,8(a0)                  ; set current output ptr
  919.      add.l      d1,d0                   ; add buffer length
  920.      move.l   d0,12(a0)                  ; store ptr to end of buffer
  921.      clr.l      16(a0)                  ; clear byte cnt
  922.      move.l   vb_CurBaud(a5),d0              ; get internal baud
  923.      lsr.l      #4,d0                   ; divide by 16
  924.      sub.l      d0,d1                   ; subtract from length
  925.      move.l   d1,20(a0)                  ; set threshold
  926.      ;
  927.      ;      Enable, set RC and return.
  928.      ;
  929.      ENABLE                       ; enable interrupts
  930.      moveq      #0,d0                   ; I/O complete
  931.      rts                          ; return
  932.      ;
  933.      ;
  934.      ;
  935.      cnop 0,4 ; align for 020+
  936. cmd_Invalid
  937.      move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; set bad status
  938.      moveq      #0,d0                   ; I/O complete
  939.      rts                          ; return
  940.      ;
  941.      ;      Returns number of bytes currently in internal buffer and
  942.      ;      current serial port status.
  943.      ;
  944.      ;      NOTE:  Not completely compatible with standard serial.device
  945.      ;      since it doesn't return the upper byte of IO_STATUS.
  946.      ;
  947.      cnop 0,4 ; align for 020+
  948. sdcmd_Query:
  949.      DISABLE                      ; disable interrupts
  950.      moveq      #0,d0                   ; clear d0
  951.      move.b   _ciabpra,d0                  ; get PR register
  952.      andi.b   #~PRTMASK,d0                  ; zap printer bits
  953.      ;
  954.      ;      To use this Set SETDSR to one.  This was done
  955.      ;      for a user whose DSR pin did not function.
  956.      ;
  957.     IFNE SETDSR
  958.      andi.b     #~(1<<CIAB_COMDSR),d0              ; set DSR
  959.     ENDC
  960.      ;
  961.      ;
  962.      ;
  963.      move.w   d0,IO_STATUS(a1)              ; store status
  964.      move.l   i_InCnt(pc),IO_ACTUAL(a1)          ; byte left in buffer
  965.      ;
  966.      ;      Enable, set RC and return.
  967.      ;
  968.      ENABLE                       ; enable interrupts
  969.      moveq      #0,d0                   ; I/O complete
  970.      rts                          ; return
  971.      ;
  972.      ;
  973.      ;
  974.      cnop 0,4 ; align for 020+
  975. sdcmd_SetParams:
  976.      ;
  977.      ;      Validate the read, write, and stop bit lengths.
  978.      ;
  979.      moveq      #8,d0                   ; get char length
  980.      cmp.b      IO_READLEN(a1),d0              ; 8 bit chars for read?
  981.      bne.b      40$                      ; nope, branch
  982.      cmp.b      IO_WRITELEN(a1),d0              ; 8 bit chars for write?
  983.      bne.b      40$                      ; nope, branch
  984.      moveq      #1,d0                   ; get stop bits
  985.      cmp.b      IO_STOPBITS(a1),d0              ; 1 stop bit?
  986.      bne.b      40$                      ; nope, branch
  987.      ;
  988.      ;      Get and validate the baud rate.
  989.      ;
  990.      move.l   IO_BAUD(a1),d1              ; get baud from I/O req
  991.      bne.b      20$                      ; specified?
  992.      move.l   vb_CurBaud(a5),d1              ; get current baud from base
  993.      bne.b      20$                      ; specified?
  994.      move.l   vb_DefBaud(a5),d1              ; get default baud from base
  995. 20$     cmpi.l   #110,d1                  ; too low?
  996.      blt.b      40$                      ; error
  997.      cmpi.l   #292000,d1                  ; too high?
  998.      bgt.b      40$                      ; error
  999.      ;
  1000.      ;      Get and validate the buffer length.
  1001.      ;
  1002.      move.l   IO_RBUFLEN(a1),d0              ; get buffer length
  1003.      bne.b      30$                      ; specified?
  1004.      move.l   vb_CurRBufLen(a5),d0              ; get current from base
  1005.      bne.b      30$                      ; specified?
  1006.      move.l   vb_DefRBufLen(a5),d0              ; get default from base
  1007.      ;
  1008. 30$     bsr.b      internalReset               ; go init baud and buffer
  1009. 35$     move.b   d0,IO_ERROR(a1)              ; set error code
  1010.      bne.b      39$
  1011.      ;
  1012.      ;      If the 7wire bit is not on, we will only use 3-wire protocol
  1013.      ;
  1014.      moveq      #0,d0                   ; clear flag
  1015.      btst      #SERB_7WIRE,IO_SERFLAGS(a1)          ; use 7wire handshaking?
  1016.      beq.b      36$                      ; nope, branch
  1017.      moveq      #1,d0                   ; set flag
  1018. 36$     move.b   d0,Handshake                  ; store flag
  1019.      ;
  1020.      ;      Set RC and return.
  1021.      ;
  1022. 39$     moveq      #0,d0                   ; I/O complete
  1023.      rts                          ; return
  1024.      ;
  1025.      ;      Invalid parm detected.
  1026.      ;
  1027. 40$     moveq      #SerErr_InvParam,d0              ; set error
  1028.      bra.b      35$                      ; go return
  1029.      ;
  1030.      ;      Reset the buffer and baud rate
  1031.      ;
  1032.      ;      Registers:  D0 = Buffer length
  1033.      ;              D1 = Baud rate
  1034.      ;
  1035.      cnop 0,4 ; align for 020+
  1036. internalReset:
  1037.      ;
  1038.      ;      Disable interrupts.
  1039.      ;
  1040.      DISABLE                      ; disable interrupts
  1041.      ;
  1042.      ;      Save buffer length and go set serper.
  1043.      ;
  1044.      move.l   d0,-(sp)                  ; save D0
  1045.      move.l   d1,d0                   ; get baud rate
  1046.      bsr.b      setPeriod                  ; go set the serper register
  1047.      move.l   (sp)+,d0                  ; restore D0
  1048.      ;
  1049.      ;      Determine if the buffer length is adequate for the selected CPS.
  1050.      ;      If not, use 64K for the length.
  1051.      ;
  1052.      move.l   vb_CurBaud(a5),d1              ; get current baud
  1053.      lsr.l      #$3,d1                  ; divide by 8
  1054.      cmp.l      d1,d0                   ; buflen > CPS
  1055.      bhi.b      10$                      ; yep, branch
  1056.      move.l   #65536,d0                  ; else use 64K
  1057.      ;
  1058. 10$     bsr.b      allocBuf                  ; go allocate a new buffer
  1059.      ;
  1060.      ;      Enable and return to caller.
  1061.      ;
  1062.      ENABLE                       ; enable interrupts
  1063.      rts                          ; return (D0 has status)
  1064.      ;
  1065.      ;      Set serial period register
  1066.      ;
  1067.      cnop 0,4 ; align for 020+
  1068. setPeriod:
  1069.      cmp.l      vb_CurBaud(a5),d0              ; current baud = new baud?
  1070.      beq.b      40$                      ; yep, just exit
  1071.      move.l   d0,vb_CurBaud(a5)              ; save new baud
  1072.      move.l   d0,d1                   ; save again
  1073.      lsl.l      #3,d0                   ; baud *= 8
  1074.      sub.l      d1,d0                   ; baud -= saved baud
  1075.      move.l   #25000000,d1                  ; get NTSC base
  1076.      cmpi.b   #50,PowerSupplyFrequency(a6)          ; PAL machine?
  1077.      bne.b      10$                      ; nope, branch
  1078.      move.l   #24772416,d1                  ; get PAL base
  1079. 10$     cmpi.l   #$FFFF,d0                  ; Divide
  1080.      ble.b      20$                      ;
  1081.      lsr.l      #5,d0                   ;
  1082.      divu.w   d0,d1                   ;
  1083.      andi.l   #$FFFF,d1                  ;
  1084.      lsr.l      #5,d1                   ;
  1085.      bra.b      30$                      ;
  1086.      cnop 0,4 ; align for 020+
  1087. 20$     divu.w   d0,d1                   ;
  1088. 30$     move.w   d1,_serper                  ; set period value
  1089. 40$     rts
  1090.      ;
  1091.      ;      Allocate new internal buffer
  1092.      ;
  1093.      cnop 0,4 ; align for 020+
  1094. allocBuf:
  1095.      cmp.l      vb_CurRBufLen(a5),d0              ; len same as previous?
  1096.      beq.b      10$                      ; yep, so no need to alloc
  1097.      move.l   d0,d1                   ; save length
  1098.      movem.l  d1/a1,-(sp)                  ; save registers
  1099.      moveq      #MEMF_PUBLIC,d1              ; public memory
  1100.      jsr      _LVOAllocMem(a6)              ; go allocate it
  1101.      movem.l  (sp)+,d1/a1                  ; restore registers
  1102.      tst.l      d0                      ; did we get it?
  1103.      beq.b      20$                      ; if zero, error
  1104.      bsr.b      freeBuf                  ; go free previous buffer
  1105.      move.l   d0,vb_CurRBuf(a5)              ; store new ptr
  1106.      move.l   d1,vb_CurRBufLen(a5)              ; and length
  1107.      bsr      cmd_Clear                  ; go setup buffer
  1108. 10$     moveq      #0,d0                   ; success
  1109. 15$     rts                          ; return
  1110. 20$     moveq      #SerErr_BufErr,d0              ; set error status
  1111.      bra.b      15$                      ; return
  1112.      ;
  1113.      ;      Free internal buffer
  1114.      ;
  1115.      cnop 0,4 ; align for 020+
  1116. freeBuf:
  1117.      movem.l  d0-d1/a0-a1,-(sp)              ; save registers
  1118.      move.l   vb_CurRBuf(a5),d0              ; is one there?
  1119.      beq.b      10$                      ; no so branch
  1120.      movea.l  d0,a1                   ; get ptr
  1121.      move.l   vb_CurRBufLen(a5),d0              ; get length
  1122.      clr.l      vb_CurRBuf(a5)              ; clear
  1123.      clr.l      vb_CurRBufLen(a5)              ; clear
  1124.      jsr      _LVOFreeMem(a6)              ; free it
  1125. 10$     movem.l  (sp)+,d0-d1/a0-a1              ; restore registers
  1126.      rts                          ; return
  1127.      ;
  1128.      ;      Checks CTS status and if clear generates a TBE interrupt or
  1129.      ;      requeues the timer request.
  1130.      ;
  1131.      ;      Entered from Exec using the MsgPort callback.
  1132.      ;
  1133.      ;      Input:   a6 = ExecBase
  1134.      ;      Output:  none
  1135.      ;
  1136.      ;      No need to preserve d0/d1/a0/a1
  1137.      ;
  1138.      cnop 0,4 ; align for 020+
  1139. timerRtn:
  1140.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1141.      ; This is the REMOVE macro
  1142.      move.l   (a1)+,a0
  1143.      move.l   (a1),a1                  ; LN_PRED
  1144.      move.l   a0,(a1)
  1145.      move.l   a1,LN_PRED(a0)
  1146.      ;
  1147.      ;      If we were breaking, reset adkcon.
  1148.      ;
  1149.      lea.l      _custom,a0                  ; get ptr to custom regs
  1150.      btst      #ADKB_UARTBRK-8,adkconr(a0)          ; were we breaking?
  1151.      beq.b      10$                      ; nope, skip reset
  1152.      ;
  1153.      move.w   #ADKF_UARTBRK,adkcon(a0)          ; stop breaking
  1154.      ;
  1155.      ;
  1156.      ;
  1157. 10$     tst.b      Handshake(pc)               ; are we handshaking?
  1158.      beq.b      20$                      ; nope, generate interrupt
  1159.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1160.      beq.b      20$                      ; yep, go start writing
  1161.      ;
  1162.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1163.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1164.      jsr      _LVOSendIO(a6)              ; go queue it
  1165.      bra.b      30$                      ; branch to return
  1166.      ;
  1167.      ;      CTS is clear so generate TBE interrupt to restart writing
  1168.      ;
  1169.      cnop 0,4 ; align for 020+
  1170. 20$     move.w   #INTF_SETCLR|INTF_TBE,intreq(a0)    ; set TBE interrupt
  1171. 30$     rts                          ; return
  1172.      ;
  1173.      ;      Non serial interrupt
  1174.      ;
  1175.      ;  a0 - custom chips base
  1176.      ;  a1 - is_Data
  1177.      cnop 0,4 ; align for 020+
  1178. level1n:
  1179.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1180.      lea      _custom,a0                  ; get ptr to custom regs
  1181.      move.w   intenar(a0),d1              ; get enabled interrupts
  1182.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1183.      movea.l  SysBase(pc),a6              ; get ExecBase
  1184.      ;
  1185.      btst      #INTB_DSKBLK,d1              ; Disk block done?
  1186.      beq.b      10$                      ; nope, branch
  1187.      ;
  1188.      movem.l  IVDSKBLK(a6),a1/a5              ; get data and code ptrs
  1189.      pea.l      20$(pc)                  ; push return address
  1190.      jmp      (a5)                      ; jump to routine
  1191.      ;
  1192. 10$     btst      #INTB_SOFTINT,d1              ; software interrupt?
  1193.      beq.b      20$                      ; nope, branch
  1194.      ;
  1195.      movem.l  IVSOFTINT(a6),a1/a5              ; get data and code ptrs
  1196.      pea.l      20$(pc)                  ; push return address
  1197.      jmp      (a5)                      ; jump to routine
  1198.      ;
  1199. 20$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1200.      rte                          ; return
  1201.      ;
  1202.      ;      Level 1 interrupt handler
  1203.      ;
  1204.      ;  a1 - is_Data
  1205.      ;
  1206.      cnop 0,4 ; align for 020+
  1207. level1:
  1208.      btst      #INTB_INTEN-8,_intenar          ; interrupts enabled?
  1209.      beq.b      35$                      ; nope, ignore
  1210.      btst      #INTB_SOFTINT,_intreqr+1          ; software interrupt?
  1211.      bne.b      level1n                  ; nope, branch
  1212.      btst      #INTB_TBE,_intreqr+1              ; xmit buffer empty?
  1213.      beq.b      level1n                  ; nope, invoke old handler
  1214.      ;
  1215.      ;      Handle "Transmit Buffer Empty" interrupt (write)
  1216.      ;
  1217.      move.w   #INTF_TBE,_intreq              ; clear interrupt
  1218.      move.l   d0,-(sp)                  ; save D0 (faster than MOVEM)
  1219.      move.l   a0,-(sp)                  ; save A0 (faster than MOVEM)
  1220.      ;
  1221.      ;      If we're not handshaking, bypass it.
  1222.      ;
  1223. 10$     tst.b      Handshake(pc)               ; are we handshaking?
  1224.      beq.b      20$                      ; nope, skip CTS test
  1225.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1226.      bne.b      40$                      ; nope, branch
  1227.      ;
  1228.      ;      If cw_Length goes negative here, we are either done with a
  1229.      ;      request or we were called as a result of a fake interrupt
  1230.      ;      to force us to get the next request going.
  1231.      ;
  1232. 20$     subq.l   #1,cw_Length                  ; decr write length
  1233.      blt.b      60$                      ; < zero, done, branch
  1234.      ;
  1235.      ;      Currently processing a request.
  1236.      ;
  1237.      movea.l  cw_Buffer(pc),a0              ; get buffer ptr
  1238.      move.w   #256,d0                  ; set stop bit
  1239.      move.b   (a0)+,d0                  ; get next byte
  1240.      move.l   a0,cw_Buffer                  ; store buffer ptr
  1241.      move.w   d0,_serdat                  ; store in serdat reg
  1242.      ;
  1243. 30$     movea.l  (sp)+,a0                  ; restore registers
  1244.      move.l   (sp)+,d0                  ; restore registers
  1245. 35$     rte                          ; return
  1246.      ;
  1247.      ;      Queue a timer request to recheck CTS status
  1248.      ;
  1249. 40$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1250.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1251.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1252.      movea.l  SysBase(pc),a6              ; get ExecBase
  1253.      jsr      _LVOSendIO(a6)              ; queue the request
  1254.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1255.      bra.b      30$                      ; go return
  1256.      ;
  1257.      ;      There aren't anymore requests, so clear and exit
  1258.      ;
  1259.      cnop 0,4 ; align for 020+
  1260. 50$     clr.l      cw_Length-Start(a6)              ; clear length
  1261.      clr.l      cw_IOReq-Start(a6)              ; clear
  1262.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1263.      bra.b      30$                      ; go return
  1264.      ;
  1265.      ;      Write request completed
  1266.      ;
  1267.      cnop 0,4 ; align for 020+
  1268. 60$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1269.      ;
  1270.      move.l   cw_IOReq(pc),d0              ; active I/O request?
  1271.      beq.b      70$                      ; nope, branch
  1272.      ;
  1273.      ;      Reply it and setup for next
  1274.      ;
  1275.      movea.l  d0,a1                   ; get I/O request
  1276.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1277.      clr.b      IO_ERROR(a1)                  ; no error
  1278.      movea.l  SysBase(pc),a6              ; get ExecBase
  1279.      jsr      _LVOReplyMsg(a6)              ; return I/O request
  1280.      ;
  1281. 70$     lea.l      Start(pc),a6                  ; get section base
  1282.      ;
  1283.      lea.l      writeQ(pc),a1               ; get ptr to write queue
  1284.      move.l   (a1),a0                  ; get head of list
  1285.      move.l   (a0),d0                  ; get successor
  1286.      beq.b      50$                      ; end of list? yep, branch
  1287.      ;
  1288.      ;      Remove the node from the list
  1289.      ;
  1290.      move.l   d0,(a1)                  ; make new head
  1291.      exg.l      d0,a0                   ; swap nodes
  1292.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1293.      ;
  1294.      move.l   d0,a1                   ; get I/O request
  1295.      ;
  1296.      ;      If it's a BREAK, then branch to process as such.
  1297.      ;
  1298.      cmpi.w   #SDCMD_BREAK,IO_COMMAND(a1)          ; BREAK command?
  1299.      beq.b      100$                      ; yep, branch
  1300.      ;
  1301.      ;      Check for absolute length
  1302.      ;
  1303.      move.l   IO_DATA(a1),a0              ; get data ptr
  1304.      moveq      #-1,d1                  ; get value
  1305.      move.l   IO_LENGTH(a1),d0              ; get length
  1306.      cmp.l      d1,d0                   ; length = -1?
  1307.      bne.b      90$                      ; nope, skip scan
  1308.      ;
  1309.      ;      Scan the data for null to calc the length
  1310.      ;
  1311.      move.l   a0,d1                   ; save data ptr
  1312.     ; Buffer size is multiple of 64bytes so we can safely move a long
  1313. 80$     move.l   (a0),d0                  ; move a long into d0
  1314.      addq.l   #1,a0                   ; update pointer
  1315.      tst.b      d0                      ; does it equal 0? (first byte)
  1316.      beq.b      81$                      ; yep, finish
  1317.      addq.l   #1,a0                   ; update pointer
  1318.      lsr.l      #8,d0                   ; shift too second byte
  1319.      tst.b      d0                      ; does it equal 0? (second byte)
  1320.      beq.b      81$                      ; yep, finish
  1321.      addq.l   #1,a0                   ; update pointer
  1322.      lsr.l      #8,d0                   ; shift too third byte
  1323.      tst.b      d0                      ; does it equal 0? (third byte)
  1324.      beq.b      81$                      ; yep, finish
  1325.      addq.l   #1,a0                   ; update pointer
  1326.      lsr.l      #8,d0                   ; shift too fourth byte
  1327.      tst.b      d0                      ; does it equal 0? (fourth byte)
  1328.      beq.b      81$                      ; yep, finish
  1329.      bra.b      80$                      ; loop
  1330.      cnop 0,4 ; align for 020+
  1331. 81$
  1332.      suba.l   d1,a0                   ; calc # of bytes
  1333.      move.l   a0,d0                   ; xfer
  1334.      movea.l  d1,a0                   ; get data ptr
  1335.      ;
  1336. 90$     move.l   d0,IO_ACTUAL(a1)              ; go ahead and set it
  1337.      move.b   IO_FLAGS(a1),d1
  1338.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1339.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1340.      move.b   d1,IO_FLAGS(a1)
  1341.      move.l   d0,cw_Length-Start(a6)          ; store length
  1342.      move.l   a0,cw_Buffer-Start(a6)          ; store buffer ptr
  1343.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1344.      ;
  1345.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1346.      bra      10$                      ; go start request
  1347.      ;
  1348.      ;      Start the BREAK.
  1349.      ;
  1350.      cnop 0,4 ; align for 020+
  1351. 100$     move.b   IO_FLAGS(a1),d1
  1352.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1353.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1354.      move.b   d1,IO_FLAGS(a1)
  1355.      clr.l      cw_Length-Start(a6)              ; clear length
  1356.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1357.      move.w   #ADKF_SETCLR|ADKF_UARTBRK,_adkcon   ; start break
  1358.      move.l   IO_BRKTIME(a1),d0              ; get break time
  1359.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1360.      move.l   d0,IOTV_TIME+TV_MICRO(a1)          ; set the timeout
  1361.      movea.l  SysBase(pc),a6              ; get ExecBase
  1362.      jsr      _LVOSendIO(a6)              ; queue the request
  1363.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1364.      bra      30$                      ; go exit
  1365.      ;
  1366.      ;      Non serial interrupt
  1367.      ;
  1368.      ;  a1 - custom chips base
  1369.      ;
  1370.      cnop 0,4 ; align for 020+
  1371. level5n:
  1372.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1373.      lea      _custom,a0                  ; get ptr to custom regs
  1374.      move.w   intenar(a0),d1              ; get enabled interrupts
  1375.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1376.      movea.l  SysBase(pc),a6              ; get ExecBase
  1377.      btst      #INTB_DSKSYNC,d1              ; Disk synchronized?
  1378.      beq.b      10$                      ; nope, branch
  1379.      movem.l  IVDSKSYNC(A6),a1/a5              ; get data and code ptrs
  1380.      jsr      (a5)                      ; branch to routine
  1381. 10$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1382.      rte                          ; return
  1383.      ;
  1384.      ;      Default Level 5 handler
  1385.      ;
  1386.      ;  a1 - custom chips base
  1387.      ;
  1388.      cnop 0,4 ; align for 020+
  1389. level5:
  1390.      btst      #INTB_INTEN-8,_intenar          ; interrupts enabled?
  1391.      beq.b      45$                      ; nope, ignore
  1392.      btst      #INTB_RBF-8,_intreqr              ; receive buffer full?
  1393.      beq.b      level5n                  ; nope, invoke old handler
  1394.      ;
  1395.      move.l   a0,-(sp)                  ; save registers
  1396.      move.l   a1,-(sp)                  ; save registers
  1397.      lea      _custom,a1                  ; get ptr to custom regs
  1398.      ;
  1399. 10$     btst      #7,serdatr(a1)              ; Overrun?
  1400.      bne.b      50$                      ; yep, branch
  1401.      ;
  1402. 20$     movea.l  i_BufIn(pc),a0              ; get current ptr
  1403.      move.b   serdatr+1(a1),(a0)+              ; store received byte
  1404.      move.w   #INTF_RBF,intreq(a1)              ; clear RBF interrupt
  1405.      addq.l   #1,i_InCnt                  ; incr bytes in buffer
  1406.      ;
  1407.      cmpa.l   i_BufEnd(pc),a0              ; hit end of buffer?
  1408.      beq.b      60$                      ; yep, branch
  1409. 30$     move.l   a0,i_BufIn                  ; store input ptr
  1410.      ;
  1411.      subq.l   #1,i_Thresh                  ; close to full buffer?
  1412.      beq.b      70$                      ; yep, branch
  1413.      ;
  1414. 40$     btst      #INTB_RBF-8,intreqr(a1)          ; receive buffer full?
  1415.      bne.b      10$                      ; yep, go get another byte
  1416.      ;
  1417.      movea.l  (sp)+,a1                  ; restore registers
  1418.      movea.l  (sp)+,a0                  ; restore registers
  1419. 45$     rte                          ; return
  1420.      ;
  1421.      ;      We've missed some data, so set overrun flag.
  1422.      ;
  1423. 50$     addq.b   #1,Overrun                  ; set overrun flag
  1424.      bra.b      20$                      ; continue
  1425.      ;
  1426.      ;      Hit physical end of buffer, so wrap to the start of the buffer.
  1427.      ;
  1428.      cnop 0,4 ; align for 020+
  1429. 60$     movea.l  i_BufPtr(pc),a0              ; get buffer ptr
  1430.      bra.b      30$                      ; continue
  1431.      ;
  1432.      ;      Hit buffer threshold, so tell other end not to send any more
  1433.      ;      data.
  1434.      ;
  1435.      cnop 0,4 ; align for 020+
  1436. 70$     tst.b      Handshake(pc)               ; are we handshaking?
  1437.      beq.b      40$                      ; nope, skip RTS
  1438.      ori.b      #1<<CIAB_COMRTS,_ciabpra          ; block further input
  1439.      bra.b      40$                      ; go return
  1440.      ;
  1441.      ;
  1442.      ;  a1 - IS_DATA
  1443.      ;  a5 - jump vector register
  1444.      ;
  1445.      cnop 0,4 ; align for 020+
  1446. level2:
  1447.      ;
  1448.      ;      If there's nothing in the buffer, there's no point in going
  1449.      ;      any further.
  1450.      ;
  1451.      tst.l      i_InCnt(pc)                  ; anything in the buffer?
  1452.      bne.b      20$                      ; yep, branch
  1453. 10$     moveq      #0,d0                   ; set Z flag
  1454.      rts                          ; return
  1455.      ;
  1456.      ;      If we've been "disabled" then get out.
  1457.      ;
  1458. 20$     tst.b      disableRead(pc)              ; internally disabled?
  1459.      bge.b      10$                      ; yep, get out of here
  1460.      lea.l      Start(pc),a5                  ; get base
  1461.      ;
  1462.      ;      If we have an active request, branch down and try to fulfill it.
  1463.      ;
  1464.      move.l   cr_IOReq(pc),d0              ; get and test active I/O
  1465.      bne.b      30$                      ; nzero, active, branch
  1466.      ;
  1467.      ;      Get first node in list and test if empty.
  1468.      ;
  1469.      move.l   (a1),a0                  ; get head of list
  1470.      move.l   (a0),d0                  ; get successor
  1471.      beq.b      10$                      ; end of list? yep, branch
  1472.      ;
  1473.      ;      Remove the node from the list
  1474.      ;
  1475.      move.l   d0,(a1)                  ; make new head
  1476.      exg.l      d0,a0                   ; swap nodes
  1477.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1478.      ;
  1479.      ;      Setup fields for processing a read request
  1480.      ;
  1481.      movea.l  d0,a1                   ; get I/O request
  1482.      move.b   IO_FLAGS(a1),d1
  1483.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1484.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1485.      move.b   d1,IO_FLAGS(a1)
  1486.      move.l   a1,cr_IOReq-Start(a5)           ; store I/O request
  1487.      move.l   IO_DATA(a1),cr_OutPtr-Start(a5)     ; get/set output ptr
  1488.      move.l   IO_LENGTH(a1),cr_Length-Start(a5)   ; get/set output count
  1489.      ;
  1490.      ;      Process an active I/O request
  1491.      ;
  1492. 30$     movea.l  SysBase(pc),a6              ; get ExecBase
  1493.      move.l   d0,a1                   ; get I/O request
  1494.      bsr.b      copyData                  ; go copy 'em
  1495.      tst.l      d0                      ; done with request?
  1496.      beq.b      10$                      ; nope, branch
  1497.      ;
  1498.      ;      the request has been satisfied, so return it.
  1499.      ;
  1500.      clr.l      cr_IOReq-Start(a5)              ; clear request
  1501.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1502.      jsr      _LVOReplyMsg(a6)              ; return I/O
  1503.      bra.b      10$
  1504.      ;
  1505.      ;      Registers:
  1506.      ;      Entry:   A1        Ptr to I/O Request
  1507.      ;           A6        ExecBase
  1508.      ;      Exit:    D0        ZERO - request not done, do not reply it
  1509.      ;                NZERO - request done, reply it
  1510.      ;
  1511.      cnop 0,4 ; align for 020+
  1512. copyData:
  1513.      ;
  1514.      ;      Process an active I/O request (or fall through from above)
  1515.      ;
  1516.      movem.l  d2-d5/a1-a5,-(sp)              ; save registers
  1517.      lea.l      Start(pc),a5                  ; get base
  1518.      movea.l  a1,a4                   ; get I/O request
  1519.      ;
  1520.      movea.l  i_BufOut(pc),a2              ; get current bufout ptr
  1521.      movea.l  cr_OutPtr(pc),a3              ; get current output ptr
  1522.      move.l   cr_Length(pc),d2              ; get current bytes needed
  1523.      move.l   i_InCnt(pc),d3              ; get current bytes in buffer
  1524.      ;
  1525.      ;      If we don't have enough bytes to satisfy the request,
  1526.      ;      set the length to the number of bytes we do have.
  1527.      ;
  1528.      cmp.l      d2,d3                   ; enuf to satisfy request?
  1529.      bge.b      15$                      ; yep, so branch
  1530.      move.l   d3,d2                   ; # to copy = # in buffer
  1531.      bra.b      15$                      ; branch to loop entry
  1532.      ;
  1533.      ;      Start of copy loop.
  1534.      ;
  1535.      cnop 0,4 ; align for 020+
  1536. 10$     movea.l  i_BufPtr(pc),a2              ; reset bufout to start
  1537.      ;
  1538.      ;      Entry point of copy loop.
  1539.      ;
  1540. 15$     move.l   d2,d3                   ; xfer # of bytes to copy
  1541.      ;
  1542.      ;      If the copy will extend past the end of the buffer, we can
  1543.      ;      only copy the number of bytes to the end this go around.
  1544.      ;
  1545.      move.l   i_BufEnd(pc),d0              ; get ptr to end of buf
  1546.      sub.l      a2,d0                   ; calc # of bytes to end
  1547.      cmp.l      d0,d3                   ; # to copy < # to end?
  1548.      blt.b      20$                      ; yep, branch
  1549.      move.l   d0,d3                   ; get bytes to end
  1550.      ;
  1551.      ;      Registers:
  1552.      ;
  1553.      ;      A2 = pointer from which data will be copied
  1554.      ;      A3 = pointer to which data will be copied
  1555.      ;      D2 = number of bytes that need to be copied
  1556.      ;      D3 = number of bytes to copy this iteration
  1557.      ;
  1558.     IFNE EOFCODE
  1559. 20$     btst      #SERB_EOFMODE,IO_SERFLAGS(a4)       ; EOFMODE requested?
  1560.      beq.b      30$                      ; nope, just go copy
  1561.      ;
  1562.      ;      EOFMODE was specified so copy characters 1 at a time until
  1563.      ;      we hit an EOF character, the output butter has filled, or
  1564.      ;      the input buffer has drained.
  1565.      ;
  1566.      move.l   d3,d0                   ; get length
  1567.      ;
  1568.      lea.l      IO_TERMARRAY(a4),a1              ; get termarry ptr
  1569. 21$     move.b   (a2)+,d1                  ; get byte
  1570.      ; This way the term char IS copied (if term char is not copied eofmode will fail)
  1571.      move.b   d1,(a3)+                  ; put in output buffer
  1572.      ;
  1573.      cmp.b      (a1),d1                  ; found term char?
  1574.      bge.b      22$                      ; possibly, branch
  1575.      cmp.b      1(a1),d1                  ; found term char?
  1576.      bge.b      22$                      ; possibly, branch
  1577.      cmp.b      2(a1),d1                  ; found term char?
  1578.      bge.b      22$                      ; possibly, branch
  1579.      cmp.b      3(a1),d1                  ; found term char?
  1580.      bge.b      22$                      ; possibly, branch
  1581.      cmp.b      4(a1),d1                  ; found term char?
  1582.      bge.b      22$                      ; possibly, branch
  1583.      cmp.b      5(a1),d1                  ; found term char?
  1584.      bge.b      22$                      ; possibly, branch
  1585.      cmp.b      6(a1),d1                  ; found term char?
  1586.      bge.b      22$                      ; possibly, branch
  1587.      cmp.b      7(a1),d1                  ; found term char?
  1588.      bgt.b      23$                      ; nope, branch
  1589. 22$     beq.b      24$                      ; term char found?
  1590.      ;
  1591.      ;      Didn't find a term character, so continue with the copy loop
  1592.      ;
  1593. 23$
  1594.      subq.l   #1,d0                   ; decr length counter
  1595.      bne.b      21$                      ; continue if more
  1596.      bra      40$                      ; done with copy, branch
  1597.      ;
  1598.      ;      We've found a termination character.
  1599.      ;
  1600.      cnop 0,4 ; align for 020+
  1601. 24$     clr.l      cr_Length-Start(a5)              ; done with request
  1602.      bra      50$                      ; branch
  1603.      cnop 0,4 ; align for 020+
  1604.     ELSE
  1605. 20$
  1606.     ENDC
  1607.      ;
  1608.      ;      EOFMODE not specified, so just do a bulk copy.
  1609.      ;
  1610.      ;      XXX POSSIBLE SPEEDUP XXX
  1611.      ;
  1612.      ;      For short copies it would be quicker to have a simple inline
  1613.      ;      loop, but what's short???  It would be different by CPU.
  1614.      ;
  1615. 30$
  1616.      move.l   d3,d0                   ; get length
  1617.      movea.l  a3,a1                   ; where to put it
  1618.      movea.l  a2,a0                   ; where to get it
  1619.  
  1620.      movem.l  d2-d7/a2-a6,-(sp)
  1621. ; we assume buffers are aligned
  1622. ; NB: buffer size is multiple of 64bytes (not contents size)
  1623. ; Copy should fit on 256 byte Inst Cache.
  1624. ; Copy loop for 1K blocks
  1625. 35$     cmp.l      #1024,d0
  1626.      blo      100$
  1627. ; Copy 1008 bytes
  1628.      movem.l  (a0)+,d1-d7/a2-a6
  1629.      movem.l  d1-d7/a2-a6,(a1)
  1630.      movem.l  (a0)+,d1-d7/a2-a6
  1631.      movem.l  d1-d7/a2-a6,48(a1)
  1632.      movem.l  (a0)+,d1-d7/a2-a6
  1633.      movem.l  d1-d7/a2-a6,96(a1)
  1634.      movem.l  (a0)+,d1-d7/a2-a6
  1635.      movem.l  d1-d7/a2-a6,144(a1)
  1636.      movem.l  (a0)+,d1-d7/a2-a6
  1637.      movem.l  d1-d7/a2-a6,192(a1)
  1638.      movem.l  (a0)+,d1-d7/a2-a6
  1639.      movem.l  d1-d7/a2-a6,240(a1)
  1640.      movem.l  (a0)+,d1-d7/a2-a6
  1641.      movem.l  d1-d7/a2-a6,288(a1)
  1642.      movem.l  (a0)+,d1-d7/a2-a6
  1643.      movem.l  d1-d7/a2-a6,336(a1)
  1644.      movem.l  (a0)+,d1-d7/a2-a6
  1645.      movem.l  d1-d7/a2-a6,384(a1)
  1646.      movem.l  (a0)+,d1-d7/a2-a6
  1647.      movem.l  d1-d7/a2-a6,432(a1)
  1648.      movem.l  (a0)+,d1-d7/a2-a6
  1649.      movem.l  d1-d7/a2-a6,480(a1)
  1650.      movem.l  (a0)+,d1-d7/a2-a6
  1651.      movem.l  d1-d7/a2-a6,528(a1)
  1652.      movem.l  (a0)+,d1-d7/a2-a6
  1653.      movem.l  d1-d7/a2-a6,576(a1)
  1654.      movem.l  (a0)+,d1-d7/a2-a6
  1655.      movem.l  d1-d7/a2-a6,624(a1)
  1656.      movem.l  (a0)+,d1-d7/a2-a6
  1657.      movem.l  d1-d7/a2-a6,672(a1)
  1658.      movem.l  (a0)+,d1-d7/a2-a6
  1659.      movem.l  d1-d7/a2-a6,720(a1)
  1660.      movem.l  (a0)+,d1-d7/a2-a6
  1661.      movem.l  d1-d7/a2-a6,768(a1)
  1662.      movem.l  (a0)+,d1-d7/a2-a6
  1663.      movem.l  d1-d7/a2-a6,816(a1)
  1664.      movem.l  (a0)+,d1-d7/a2-a6
  1665.      movem.l  d1-d7/a2-a6,864(a1)
  1666.      movem.l  (a0)+,d1-d7/a2-a6
  1667.      movem.l  d1-d7/a2-a6,912(a1)
  1668.      movem.l  (a0)+,d1-d7/a2-a6
  1669.      movem.l  d1-d7/a2-a6,960(a1)
  1670. ; Copy 16 bytes
  1671.      movem.l  (a0)+,d1-d4
  1672.      movem.l  d1-d4,1008(a1)
  1673.      lea.l      1024(a1),a1
  1674.      sub.l      #1024,d0
  1675.      bne      35$
  1676.      bra.b      105$
  1677.      cnop 0,4 ; align for 020+
  1678. 100$     move.l  SysBase(pc),a6
  1679.      jsr     _LVOCopyMem(a6)
  1680. 105$     movem.l (sp)+,d2-d7/a2-a6
  1681.      adda.l   d3,a2                   ; update bufout
  1682.      adda.l   d3,a3                   ; update outptr
  1683.      ;
  1684.      ;      Fall through and entered from EOFMODE loop
  1685.      ;
  1686.      ;      If the following calculation results in a value greater than
  1687.      ;      zero, then we have a buffer wrap and need to process the
  1688.      ;      remaining bytes at the beginning of the buffer.
  1689.      ;
  1690. 40$     sub.l      d3,d2                   ; calc bytes left to copy
  1691.      bgt      10$                      ; >0, more to copy, branch
  1692.      ;
  1693.      ;
  1694.      ;
  1695. 50$     move.l   a3,d1                   ; get outptr
  1696.      sub.l      cr_OutPtr(pc),d1              ; calc length
  1697.      move.l   a3,cr_OutPtr-Start(a5)          ; update outptr
  1698.      ;
  1699.      ;      Update output ptr and I/O request
  1700.      ;
  1701.      move.l   a2,i_BufOut-Start(a5)           ; store bufout ptr
  1702.      add.l      d1,IO_ACTUAL(a4)              ; update I/O request
  1703.      ;
  1704.      ;      Update number of bytes left in the buffer.
  1705.      ;
  1706.      sub.l      d1,i_InCnt-Start(a5)              ; calc bytes left in buffer
  1707.      ;
  1708.      ;      If the threshold becomes positive here, then, if requested,
  1709.      ;      tell the other end that it's okay to start sending more data.
  1710.      ;
  1711.      add.l      d1,i_Thresh-Start(a5)           ; calc thresh and test
  1712.      ble.b      60$                      ; <= 0, need more data, skip
  1713.      tst.b      Handshake(pc)               ; are we handshaking?
  1714.      beq.b      60$                      ; nope, skip RTS
  1715.      andi.b   #~(1<<CIAB_COMRTS),_ciabpra          ; ready to recieve more data
  1716.      ;
  1717.      ;      Set error if we've had any overruns.
  1718.      ;
  1719. 60$     tst.b      Overrun(pc)                  ; did overrun occur?
  1720.      beq.b      70$                      ; nope, branch
  1721.      clr.b      Overrun-Start(a5)              ; reset overrun flag
  1722.      move.b   #SerErr_LineErr,IO_ERROR(a4)          ; set error code
  1723.      ;
  1724.      ;      Calc number of bytes left to copy.  If the result is greater
  1725.      ;      than zero, then we have more to copy so return an incomplete
  1726.      ;      status.
  1727.      ;
  1728. 70$     moveq      #0,d0                   ; assume I/O incomplete
  1729.      sub.l      d1,cr_Length-Start(a5)          ; update length and test
  1730.      bgt.b      90$                      ; >0, more to do, branch
  1731.      ;
  1732.      ;      We've completed the I/O request either by copying the requested
  1733.      ;      of bytes or by finding an EOFMODE character, so return a "reply"
  1734.      ;      status.
  1735.      ;
  1736.      moveq      #1,d0                   ; indicate reply
  1737.      ;
  1738.      ;      Restore and exit
  1739.      ;
  1740. 90$     movem.l  (sp)+,d2-d5/a1-a5              ; restore registers
  1741.      rts                          ; return (status in D0)
  1742.      ;
  1743.      ;      Align data
  1744.      ;
  1745.      CNOP      0,4
  1746.      ;
  1747.      ;
  1748.      ;
  1749. Init:
  1750.      DC.L      sizeof_Base8n1
  1751.      DC.L      funcTab
  1752.      DC.L      dataTab
  1753.      DC.L      InitRoutine
  1754.      ;
  1755.      ;
  1756.      ;
  1757. funcTab:
  1758.      DC.W      -1
  1759.      DC.W      dev_Open-funcTab
  1760.      DC.W      dev_Close-funcTab
  1761.      DC.W      dev_Expunge-funcTab
  1762.      DC.W      dev_Null-funcTab
  1763.      DC.W      dev_BeginIO-funcTab
  1764.      DC.W      dev_AbortIO-funcTab
  1765.      DC.W      -1
  1766.      ;
  1767.      ;
  1768.      ;
  1769. dataTab:
  1770.      INITBYTE LN_TYPE,NT_DEVICE
  1771.      INITLONG LN_NAME,Name
  1772.      INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
  1773.      INITWORD LIB_VERSION,VERSION
  1774.      INITWORD LIB_REVISION,REVISION
  1775.      INITLONG LIB_IDSTRING,IdString
  1776.      DC.W      0
  1777.      ;
  1778.      ;      String Constants
  1779.      ;
  1780. miscresource:
  1781.      DC.B      "misc.resource",0
  1782. timerdevice:
  1783.      DC.B      "timer.device",0
  1784. intuitlib:
  1785.      DC.B      "intuition.library",0
  1786. Name:
  1787.      DC.B      "8n1.device",0
  1788. IdString:
  1789.      VSTRING
  1790.      ;
  1791.      ;      End of checksummed area.  (Realigns data too!)
  1792.      ;
  1793. ENDTag:
  1794.      CNOP      0,4
  1795.      ;
  1796.      ;      Global SysBase (Use instead of _AbsExecBase for speed)
  1797.      ;
  1798. SysBase:
  1799.      DC.L      0
  1800.      ;
  1801.      ;      Internal buffer tracking (DO NOT CHANGE THE ORDER!!!!)
  1802.      ;
  1803. i_BufPtr:
  1804.      DC.L      0
  1805. i_BufIn:
  1806.      DC.L      0
  1807. i_BufOut:
  1808.      DC.L      0
  1809. i_BufEnd:
  1810.      DC.L      0
  1811. i_InCnt:
  1812.      DC.L      0
  1813. i_Thresh:
  1814.      DC.L      0
  1815.      ;
  1816.      ;      Used while processing a read request.
  1817.      ;
  1818. cr_IOReq:
  1819.      DC.L      0
  1820. cr_OutPtr:
  1821.      DC.L      0
  1822. cr_Length:
  1823.      DC.L      0
  1824.      ;
  1825.      ;      List head for read requests
  1826.      ;
  1827. readQ:
  1828.      DC.L      readQ+MLH_TAIL
  1829.      DC.L      0
  1830.      DC.L      readQ
  1831.      ;
  1832.      ;      Write control.
  1833.      ;
  1834. cw_Length:
  1835.      DC.L      0
  1836. cw_Buffer:
  1837.      DC.L      0
  1838. cw_IOReq:
  1839.      DC.L      0
  1840.      ;
  1841.      ;      List head for write requests
  1842.      ;
  1843. writeQ:
  1844.      DC.L      writeQ+MLH_TAIL
  1845.      DC.L      0
  1846.      DC.L      writeQ
  1847.      ;
  1848.      ;
  1849.      ;
  1850. timerPort:
  1851.      DC.L      0                      ; LN_SUCC
  1852.      DC.L      0                      ; LN_PRED
  1853.      DC.B      NT_MSGPORT                  ; LN_TYPE
  1854.      DC.B      0                      ; LN_PRI
  1855.      DC.L      0                      ; LN_NAME
  1856.      DC.B      3                      ; MP_FLAGS (undoc'ed)
  1857.      DC.B      0                      ; MP_SIGBIT
  1858.      DC.L      timerRtn                  ; MP_SIGTASK
  1859.      DC.L      timerPort+MP_MSGLIST+LH_TAIL          ; LH_HEAD
  1860.      DC.L      0                      ; LH_TAIL
  1861.      DC.L      timerPort+MP_MSGLIST              ; LH_TAILPRED
  1862.      DC.B      0                      ; LH_TYPE
  1863.      DC.B      0                      ; LH_pad
  1864.      DC.W      0                      ; long align
  1865.      ;
  1866.      ;
  1867.      ;
  1868. timerReq:
  1869.      DC.L      0                      ; LN_SUCC
  1870.      DC.L      0                      ; LN_PRED
  1871.      DC.B      NT_MESSAGE                  ; LN_TYPE
  1872.      DC.B      0                      ; LN_PRI
  1873.      DC.L      0                      ; LN_NAME
  1874.      DC.L      timerPort                  ; MN_REPLYPORT
  1875.      DC.W      IOTV_SIZE                  ; MN_LENGTH
  1876.      DC.L      0                      ; IO_DEVICE
  1877.      DC.L      0                      ; IO_UNIT
  1878.      DC.W      TR_ADDREQUEST               ; IO_COMMAND
  1879.      DC.B      0                      ; IO_FLAGS
  1880.      DC.B      0                      ; IO_ERROR
  1881.      DC.L      0                      ; TV_SECS
  1882.      DC.L      0                      ; TV_MICROS
  1883.      ;
  1884.      ;
  1885.      ;
  1886. VBInterrupt:
  1887.      DC.L      0                      ; LN_SUCC
  1888.      DC.L      0                      ; LN_PRED
  1889.      DC.B      NT_INTERRUPT                  ; LN_TYPE
  1890.      DC.B      0                      ; LN_PRI
  1891.      DC.L      Name                      ; LN_NAME
  1892.      DC.L      readQ                   ; IS_DATA
  1893.      DC.L      level2                  ; IS_CODE
  1894.      ;
  1895.      ;      Global flags
  1896.      ;
  1897. Overrun:
  1898.      DC.B      0
  1899. Handshake:
  1900.      DC.B      1
  1901. disableRead:
  1902.      DC.B      -1
  1903.      ;
  1904.      ;
  1905.      ;
  1906.      END
  1907.  
  1908.